home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
internet
/
atmtim11.zip
/
ATOMTIME.C
next >
Wrap
C/C++ Source or Header
|
1996-06-05
|
7KB
|
253 lines
// Atomic Time
// 6-6-96 Tom Wuttke (tom@berksys.com)
// Based on a VB app by Brad Greer
//
// Freeware
//
// A simple WIN32 Winsock app that sets the current system time based
// on that of a remote UNIX server using port 37. It is only accurate to
// 1 second.
//
// Command line
// arg1 - the remote server's IP address
// (do not begin this with - or + characters if you are specifying
// a server)
// arg2 - minute offset. adds or subtracts this many minutes to correct for any
// unknown time zone problems
//
// if arg2 is omitted, I assume you want the normal time correction
// if there are no arguments, I assume the remote server is tycho.usno.navy.mil,
// a server based on military time
// if arg1 begins with a + or a -, I assume it is really arg2, and arg1 is
// the default server
//
// Example command lines:
// AtomTime.exe tycho.usno.navy.mil -120
// AtomTime.exe mail
// AtomTime.exe 128.192.202.215
// AtomTime +60
//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock.h>
#include <time.h>
#include <mmsystem.h>
#include <stdlib.h>
char sTitle[] = "AtomicTime";
#pragma argsused
int PASCAL WinMain(HANDLE hInst, HANDLE hStupid, LPSTR sCommandLine, int mode)
{
WSADATA WSAData;
int err;
struct hostent* volatile aHost;
SOCKADDR_IN sinClient, sinServer;
SOCKET s;
struct timeval timeToWait;
fd_set setRead;
DWORD remoteTime, localTime, timeDelay;
int tweakMinutes = 0;
int diff;
char sMessage[150];
char *sServerIP = strtok(sCommandLine, " \t\\/");
char *sDelay = strtok(NULL, " \t\\/");
// Initialize Windows sockets version 1.01
//
err = WSAStartup(0x101, &WSAData);
if (err)
{
MessageBox(0, "Could not open windows sockets.", sTitle, 0);
goto Problem1;
}
// This address is taken from tycho.usno.navy.mil
//
sinServer.sin_addr.S_un.S_addr = 0xEF2905C0UL;
if (sServerIP)
{
// See if it is a numerical IP number
//
if (*sServerIP == '+' || *sServerIP == '-')
{
sDelay = sServerIP;
}
else
{
sinServer.sin_addr.S_un.S_addr = ntohl(inet_addr(sServerIP));
if (sinServer.sin_addr.S_un.S_addr == INADDR_NONE)
{
// Otherwise, look up the address using DNS
//
aHost = gethostbyname(sServerIP);
if (aHost->h_addrtype != AF_INET)
{
MessageBox(0, "Bogus Address", sTitle, 0);
goto Problem2;
}
sinServer.sin_addr.S_un.S_addr = *((LPDWORD)aHost->h_addr_list[0]);
}
}
// If there is a second command line argument, it is the
// time offset in minutes
//
if (sDelay)
{
if (*sDelay == '+')
{
sDelay++;
}
tweakMinutes = atoi(sDelay);
}
}
// Set up for TCP/IP on port 37.
//
// Port 37 will return a 4-byte long integer every time a connection
// is established. This long integer is usually the number of seconds
// past 1/1/1970, or past 1/1/1900
//
sinServer.sin_family = AF_INET;
sinServer.sin_port = htons(37);
// Locally, we don't care about the port.
//
sinClient.sin_family = AF_INET;
sinClient.sin_addr.S_un.S_addr = INADDR_ANY;
sinClient.sin_port = 0;
// Create a socket
//
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
{
MessageBox(0, "Cannot create socket.", sTitle, 0);
goto Problem2;
}
// Bind the socket to our local machine
//
err = bind(s, (const struct sockaddr FAR *)&sinClient, sizeof(sinClient));
if (err)
{
MessageBox(0, "Cannot bind socket to local machine.", sTitle, 0);
goto Problem3;
}
// Begin computing the transmission delay.
// This is only useful when the delay is around 4 to 8 seconds,
// since the granularity of this clock is 1 second.
//
timeDelay = timeGetTime();
// Connect to the remote machine on port 37
//
err = connect(s, (const struct sockaddr FAR *)&sinServer, sizeof(sinClient));
if (err)
{
MessageBox(0, "Cannot connect to remote machine.", sTitle, 0);
goto Problem3;
}
// Timeout after 15 seconds
//
timeToWait.tv_sec = 15;
timeToWait.tv_usec = 1;
// We only want status on 1 socket
//
setRead.fd_count = 1;
setRead.fd_array[0] = s;
// Wait for notification that we have received new data, or timeout
//
switch (select(0, &setRead, NULL, NULL, &timeToWait))
{
case 0:
MessageBox(0, "Remote machine timeout", sTitle, 0);
goto Problem3;
case SOCKET_ERROR:
MessageBox(0, "Cannot read from remote machine.", sTitle, 0);
goto Problem3;
}
// Read in the new data
//
err = recv(s, (char FAR *)&remoteTime, 4, 0);
if (err != 4)
{
MessageBox(0, "Cannot read 4 byte time code from remote machine.", sTitle, 0);
goto Problem3;
}
// Use the connection delay/4 as an adjustment (TCP connections have 2 round
// trips to make)
//
timeDelay = (timeGetTime() - timeDelay + 500) / 4000;
// The remote time will be in the wrong byte order, so fix it and add the
// transmission delay
//
remoteTime = ntohl(remoteTime) + timeDelay + tweakMinutes * 60;
// Grab the current system clock's time and compute the difference
//
localTime = time(NULL);
diff = remoteTime - localTime;
// If we are off by more than a year, chances are the remote server is using
// a different bias than 1/1/1970.
//
if (abs(diff) > 3600 * 24 * 365)
{
// Make it relative to 1900 then
// Notice the 17 leap years from 1900 to 1970, 1900 was NOT a leap year
//
remoteTime -= ((365UL * 70 + 17) * 3600 * 24);
diff = remoteTime - localTime;
}
// If we are off by more than 30 minutes, warn the user - since there may be
// a time zone or daylight saving problem.
//
if (abs(diff) > 1800)
{
char sRemoteTime[30], sLocalTime[30];
wsprintf(sRemoteTime, ctime((const time_t *)&remoteTime));
wsprintf(sLocalTime, ctime((const time_t *)&localTime));
wsprintf(sMessage, "Remote Time is %s\nLocal Time is %s\n"
"The time zone might be incorrect.\nAre you sure"
" you want to set the system clock\nto the remote time?",
sRemoteTime, sLocalTime);
if (MessageBox(0, sMessage, sTitle, MB_YESNO) == IDNO)
{
goto Problem3;
}
}
// Recompute the current system time plus the required adjustment, and set
// the user's system time.
//
localTime = time(NULL) + diff;
stime((time_t *)&localTime);
// Shutdown
Problem3:
closesocket(s);
Problem2:
WSACleanup();
Problem1:
return 0;
}